<?php
/**
 * Created by PhpStorm.
 * User: xh
 * Date: 2016-07-26
 * Time: 14:55
 */

namespace Common\Model;
use Think\Log;

/**
 * ProcessMaker 集成工作流模块
 * Class PmWorkFlowModel
 * @package Common\Model
 */
class PmWorkFlowModel {

    //清除php S 缓存的用户信息
    public function cleanUserCache(){
        $uid = is_login();
        S("pm_access_token_".$uid,null);
        S("pm_refresh_token_".$uid,null);
        S("pm_usr_uid_".$uid,null);
    }
 //登录
 public function pmRestLogin($uid,$username, $password) {
        $pmServer = C('PMWORKFLOW_CONFIG.SERVER');
        $pmWorkspace = C('PMWORKFLOW_CONFIG.WORKSAPCE');
        $pmKey=C('PMWORKFLOW_CONFIG.PM_ENCRYPT_KEY');
        $password=pmPwdEncrypt($password,'DECODE',$pmKey,0);   //解密
        $postParams = array(
            'grant_type'    => 'password',
            'scope'         => '*',       //set to 'view_process' if not changing the process
            'client_id'     =>C('PMWORKFLOW_CONFIG.CLIENT_ID'),
            'client_secret' => C('PMWORKFLOW_CONFIG.CLIENT_SECRET'),
            'username'      => $username,
            'password'      =>$password
        );
        $ch = curl_init("$pmServer/$pmWorkspace/oauth2/token");
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $postParams);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        $oToken = json_decode(curl_exec($ch));
        $httpStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        $redate['status'] = 0;
        if ($httpStatus != 200) {
            Log::record( "Error in HTTP status code: $httpStatus\n");
            $redate['msg'] = 'HTTP error code:'.$httpStatus;
            return $redate;
        }
        elseif (isset($oToken->error)) {
            Log::record("Error logging into $pmServer:\n" .
                "Error:       {$oToken->error}\n" .
                "Description: {$oToken->error_description}\n");
            $redate['msg'] = 'logging error:'.$oToken->error;
        }
        else {
            //At this point $oToken->access_token can be used to call REST endpoints.

            //If planning to use the access_token later, either save the access_token
            //and refresh_token as cookies or save them to a file in a secure location.

            //If saving them as cookies:
            /*setcookie("access_token",  $oToken->access_token,  time() + 86400);
            setcookie("refresh_token", $oToken->refresh_token); //refresh token doesn't expire
            setcookie("client_id",     $clientId);
            setcookie("client_secret", $clientSecret);*/

            //If saving to a file:
            //file_put_contents("/secure/location/oauthAccess.json", json_encode($tokenData));
            //存放到缓存
            S("pm_access_token_".$uid,$oToken->access_token,$oToken->expires_in);
            S("pm_refresh_token_".$uid,$oToken->refresh_token);
            $redate['status'] = 1;
            $redate['msg'] = 'success';
            $redate['access_token'] = $oToken->access_token;
        }
        return $redate;
    }

    /*Function to obtain a new access token, using a refresh token. If the parameters are not specified
    then get them from the cookie if they exist. The new access token is set as a cookie available at $_COOKIE["access_token"]
    Parameters:
      clientId:     The cliend ID.
      clientSecret: The client secret code.
      refreshToken: The refreshToken from a previous call to /oauth2/token endpoint.
    Return value:
      Object returned by /oauth2/token endpoint, which either contains access token or error message.*/
  //刷新token
  private  function pmRestRefresh($uid,$refreshToken=null) {
        $pmServer = C('PMWORKFLOW_CONFIG.SERVER');
        $pmWorkspace = C('PMWORKFLOW_CONFIG.WORKSAPCE');

        $refreshToken = ($refreshToken === null) ? S("pm_refresh_token_".$uid) : $refreshToken;
        if(empty($refreshToken)){
            $redate['status'] = 0;
            $redate['msg'] = 'refresh token is not exist';
            return $redate;
        }

        $aVars = array(
            'grant_type'    => 'refresh_token',
            'client_id'     =>C('PMWORKFLOW_CONFIG.CLIENT_ID'),
            'client_secret' => C('PMWORKFLOW_CONFIG.CLIENT_SECRET'),
            'refresh_token' => $refreshToken
        );

        $ch = curl_init("$pmServer/$pmWorkspace/oauth2/token");
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $aVars);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        $oToken = json_decode(curl_exec($ch));
        $httpStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        $redate['status'] = 0;
        if ($httpStatus != 200) {
            Log::record( "Error in HTTP status code: $httpStatus\n");
            $redate['msg'] = 'HTTP error code:'.$httpStatus;
            return $redate;
        }
        elseif (isset($oToken->error)) {
            Log::record("Error logging into $pmServer:\n" .
                "Error:       {$oToken->error}\n" .
                "Description: {$oToken->error_description}\n");
            $redate['msg'] = 'logging error:'.$oToken->error;
        }
        else {
            //Save access token as a cookie that expires in 86400 seconds:
            //setcookie("access_token",  $oToken->access_token, time() + 86400);
            //存放到缓存
            S("pm_access_token_".$uid,$oToken->access_token,$oToken->expires_in);
            $redate['status'] = 1;
            $redate['msg'] = 'success';
            $redate['access_token'] = $oToken->access_token;
            //If saving to a file:
            //file_put_contents("/secure/location/oauthAccess.json", json_encode($oToken));
        }
        return $redate;
    }

    /*Function to call a ProcessMaker REST endpoint and return the HTTP status code and
    response if any.
    Parameters:
     $method:      HTTP method: "GET", "POST", "PUT" or "DELETE"
     $endpoint:    The PM endpoint, not including the server's address and port number.
                   Ex: "/api/1.0/workflow/cases"
     $aVars:       Optional. Associative array containing the variables to use in the request
                   if "POST" or "PUT" method.
     $accessToken: Optional. The access token, which comes from oauth2/token. If not defined
                   then uses the access token in $_COOKIE['access_token']
    Return Value:
     object {
        response: Response from REST endpoint, decoded with json_decode().
        status:   HTTP status code: 200 (OK), 201 (Created), 400 (Bad Request), 404 (Not found), etc.
     }
    //通用请求方法                                                                                       */
    function pmRestRequest($method, $endpoint, $aVars = null, $accessToken = null) {
        $pmServer = C('PMWORKFLOW_CONFIG.SERVER');

        //add beginning / to endpoint if it doesn't exist:
        if (!empty($endpoint) and $endpoint[0] != "/")
            $endpoint = "/" . $endpoint;

        $ch = curl_init($pmServer . $endpoint);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization: Bearer " . $accessToken));
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $method = strtoupper($method);

        switch ($method) {
            case "GET":
                break;
            case "DELETE":
                curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
                break;
            case "PUT":
                curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
            case "POST":
                curl_setopt($ch, CURLOPT_POST, 1);
                if(!empty($aVars)){
                    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($aVars));
                }
                break;
            default:
                throw new \Exception("Error: Invalid HTTP method '$method' $endpoint");
        }

        $oRet = new \StdClass;
        $oRet->response = json_decode(curl_exec($ch));
        $oRet->status   = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($oRet->status == 401) { //if session has expired or bad login:
            Log::record($endpoint.' response error code:401,may be access token is timeout');
            /*header("Location: loginForm.php"); //change to match your login method
            die();*/
        }
        elseif ($oRet->status != 200 and $oRet->status != 201) { //if error
            if ($oRet->response and isset($oRet->response->error)) {
                Log::record( "Error in $pmServer:\nCode: {$oRet->response->error->code}\n" .
                    "Message: {$oRet->response->error->message}\n");
            }
            else {
                Log::record( "Error: HTTP status code: $oRet->status\n");
            }
        }

        return $oRet;
    }

    /**
     * 获取当前用户的工作流令牌，如果没有同步用户到工作流则会抛出异常
     * @throws \Exception
     */
    public function getPmToken(){
        $uid = is_login();
        $token = S("pm_access_token_".$uid);
        $pm_usr_id = S("pm_usr_uid_".$uid);
        if(empty($token)){
            $redata = $this->pmRestRefresh($uid);
            //刷新token成功会返回token
            if($redata['status'] == 1){
                $token = $redata['access_token'];
            }else{
                //重新登录
                //获取用户和密码
                $user = M('ucenter_member')->where(array('id'=>$uid))->field('username,pm_pwd,pm_usr_uid')->find();
                if($user && !empty($user['pm_usr_uid'])){
                    $redata = $this->pmRestLogin($uid,$user['username'],$user['pm_pwd']);
                    $token = $redata['access_token'];
                    S("pm_usr_uid_".$uid,$user['pm_usr_uid']);
					$pm_usr_id = $user['pm_usr_uid'];
                }else{
                    Log::record("Error:获取用户的pm_usr_uid失败,当前用户[$uid]可能没有同步到工作流用户系统中");
                    throw new \Exception("Error:获取用户的pm_usr_uid失败,当前用户[$uid]可能没有同步到工作流用户系统中");
                }
            }
			
        }

        if(empty($token)){
            Log::record("Error:获取token失败,当前用户[$uid]可能没有同步到工作流用户系统中");
            throw new \Exception("Error:获取token失败,当前用户[$uid]可能没有同步到工作流用户系统中");
        }else if(empty($pm_usr_id)){
            $user = M('ucenter_member')->where(array('id'=>$uid))->field('username,password,pm_usr_uid')->find();
            if($user && !empty($user['pm_usr_uid'])){
                S("pm_usr_uid_".$uid,$user['pm_usr_uid']);
            }else{
                Log::record("Error:获取用户的pm_usr_uid失败,当前用户[$uid]可能没有同步到工作流用户系统中");
                //throw new \Exception("Error:获取用户的pm_usr_uid失败,当前用户[$uid]可能没有同步到工作流用户系统中");
            }
        }
        return $token;
    }

    // ========   公共方法结束   =====

    // ========   用户相关方法开始 ========
    /**
     * 同步进销存的用户组到pm用户组系统中
     *
     * @param $group 进销存用户组对象，一定有内容的字段：id，title,status，另外pm_grp_uid字段如果是修改则必须有
     * @return mixed  返回操作结果数组 status 为成功或失败状态，1成功，0失败。msg为操作信息
     */
    public function sychronGroup($group){
        $pmWorkspace = C('PMWORKFLOW_CONFIG.WORKSAPCE');
        $token = $this->getPmToken();
        $redata['status'] = 0;
        //新增组
        if(empty($group['pm_grp_uid'])){
            $postParams = array(
                'grp_title'  => $group['title'],
                'grp_status' => $group['status'] == 1 ? "ACTIVE" : "INACTIVE",
            );
            $oRet = $this->pmRestRequest("post", "/api/1.0/{$pmWorkspace}/group", $postParams, $token);
            if ($oRet->status == 201) {
                $grp_uid = $oRet->response->grp_uid;
                //更新回分组
                M('auth_group')->where(array('id'=>$group['id']))->save(array('pm_grp_uid'=>$grp_uid));
                $redata['status'] = 1;
				$redata['pm_grp_uid'] = $grp_uid;
                $redata['msg'] = "同步添加用户组成功";
            }else{
                if ($oRet->response and isset($oRet->response->error)) {
                    Log::record( "Sychron group Error: {$oRet->response->error->code}\n" .
                        "Message: {$oRet->response->error->message}\n");
                    $redata['msg'] = "同步添加用户组错误: {$oRet->response->error->message}";
                }
                else {
                    Log::record( "Sychron group Error: HTTP status code: $oRet->status\n");
                    $redata['msg'] = "同步添加用户组错误: HTTP status code: $oRet->status";
                }
            }
        }else{
            //修改组
            $postParams = array(
                'grp_title'  => $group['title'],
                'grp_status' => $group['status'] == 1 ? "ACTIVE" : "INACTIVE",
            );
            $oRet = $this->pmRestRequest("put", "/api/1.0/{$pmWorkspace}/group/{$group['pm_grp_uid']}", $postParams, $token);
            if ($oRet->status == 200) {
                $redata['status'] = 1;
				$redata['pm_grp_uid'] = $group['pm_grp_uid'];
                $redata['msg'] = "同步修改用户组成功";
            }else{
                if ($oRet->response and isset($oRet->response->error)) {
                    Log::record( "Sychron group Error: {$oRet->response->error->code}\n" .
                        "Message: {$oRet->response->error->message}\n");
                    $redata['msg'] = "同步修改用户组错误: {$oRet->response->error->message}";
                }
                else {
                    Log::record( "Sychron group Error: HTTP status code: $oRet->status\n");
                    $redata['msg'] = "同步修改用户组错误: HTTP status code: $oRet->status";
                }
            }

        }
        return $redata;
    }

    /**
     * 同步用户到pm用户中
     * @param $ucmember 进销存用户对象，一定有内容的字段：id，username,password,email,nickname,status，另外pm_usr_uid字段如果是修改则必须有
     * @return mixed  返回操作结果数组 status 为成功或失败状态，1成功，0失败。msg为操作信息
     * @throws \Exception
     */
    public function sychronUser($ucmember){
        $pmWorkspace = C('PMWORKFLOW_CONFIG.WORKSAPCE');
        $token = $this->getPmToken();
        $redata['status'] = 0;
        $postParams = array(
            'usr_username'   => $ucmember["username"],
            'usr_firstname'  => $ucmember["nickname"],
            'usr_lastname'   => $ucmember["nickname"],
            'usr_email'      => $ucmember["email"],
            'usr_due_date'   => "2020-12-31",
            'usr_status'     => $ucmember['status'] == 1 ? "ACTIVE" : "INACTIVE",
            'usr_role'       => "PROCESSMAKER_OPERATOR",
            'usr_new_pass'   => $ucmember["password"],
            'usr_cnf_pass'   => $ucmember["password"]
        );
        //新增用户
        if(empty($ucmember['pm_usr_uid'])){
            $oRet = $this->pmRestRequest("post", "/api/1.0/{$pmWorkspace}/user", $postParams, $token);
            if ($oRet->status == 201) {
                $usr_uid = $oRet->response->USR_UID;
                Log::record( "suid:{$usr_uid};") ;
                //更新回分组
                M('ucenter_member')->where(array('id'=>$ucmember['id']))->save(array('pm_usr_uid'=>$usr_uid,'pm_status'=>1));
                $redata['status'] = 1;
				$redata['pm_usr_uid'] = $usr_uid;
                $redata['msg'] = "同步添加用户成功";
                $redata['pm_usr_uid'] = $usr_uid;  //同步用户工作流id
            }else{
                if ($oRet->response and isset($oRet->response->error)) {
                    Log::record( "Sychron user Error: {$oRet->response->error->code}\n" .
                        "Message: {$oRet->response->error->message}\n");
                    $redata['msg'] = "同步添加用户错误: {$oRet->response->error->message}";
                }
                else {
                    Log::record( "Sychron user Error: HTTP status code: $oRet->status\n");
                    $redata['msg'] = "同步添加用户错误: HTTP status code: $oRet->status";
                }
            }
        }else{
            $oRet = $this->pmRestRequest("put", "/api/1.0/{$pmWorkspace}/user/{$ucmember['pm_usr_uid']}", $postParams, $token);
            if ($oRet->status == 200) {
                $redata['status'] = 1;
				$redata['pm_usr_uid'] = $ucmember['pm_usr_uid'];
                $redata['msg'] = "同步修改用户成功";
            }else{
                if ($oRet->response and isset($oRet->response->error)) {
                    Log::record( "Sychron user Error: {$oRet->response->error->code}\n" .
                        "Message: {$oRet->response->error->message}\n");
                    $redata['msg'] = "同步修改用户错误: {$oRet->response->error->message}";
                }
                else {
                    Log::record( "Sychron user Error: HTTP status code: $oRet->status\n");
                    $redata['msg'] = "同步修改用户错误: HTTP status code: $oRet->status";
                }
            }

        }
        return $redata;
    }

    /**
     * 将用户分配到pm的用户组
     * @param $pm_usr_uid pm中的用户id
     * @param $pm_grp_uid pm中的用户组id
     * @return mixed 返回操作数组 status 为成功或失败状态，1成功，0失败。msg为操作信息
     * @throws \Exception
     */
    public function assignUserToPmGroup($pm_usr_uid,$pm_grp_uid){
        $pmWorkspace = C('PMWORKFLOW_CONFIG.WORKSAPCE');
        $token = $this->getPmToken();
        $redata['status'] = 0;
        $postParams = array(
            'usr_uid'   => $pm_usr_uid
        );
        $oRet = $this->pmRestRequest("post", "/api/1.0/{$pmWorkspace}/group/{$pm_grp_uid}/user", $postParams, $token);
        if ($oRet->status == 201) {
            $redata['status'] = 1;
            $redata['msg'] = "将用户分配到用户组成功";
        }else{
            if ($oRet->response and isset($oRet->response->error)) {
                Log::record( "将用户分配到用户组错误: {$oRet->response->error->code}\n" .
                    "Message: {$oRet->response->error->message}\n");
                $redata['msg'] = "将用户分配到用户组错误: {$oRet->response->error->message}";
            }
            else {
                Log::record( "将用户分配到用户组错误: HTTP status code: $oRet->status\n");
                $redata['msg'] = "将用户分配到用户组错误: HTTP status code: $oRet->status";
            }
        }
        return $redata;
    }

    /**
     * 将用户从pm的用户组删除
     * @param $pm_usr_uid pm中的用户id
     * @param $pm_grp_uid pm中的用户组id
     * @return mixed 返回操作数组 status 为成功或失败状态，1成功，0失败。msg为操作信息
     * @throws \Exception
     */
    public function unAssignUserToPmGroup($pm_usr_uid,$pm_grp_uid){
        $pmWorkspace = C('PMWORKFLOW_CONFIG.WORKSAPCE');
        $token = $this->getPmToken();
        $redata['status'] = 0;

        $oRet = $this->pmRestRequest("delete", "/api/1.0/{$pmWorkspace}/group/{$pm_grp_uid}/user/{$pm_usr_uid}", null, $token);
        if ($oRet->status == 200) {
            $redata['status'] = 1;
            $redata['msg'] = "将用户从到用户组删除成功";
        }else{
            if ($oRet->response and isset($oRet->response->error)) {
                Log::record( "将用户从到用户组删除错误: {$oRet->response->error->code}\n" .
                    "Message: {$oRet->response->error->message}\n");
                $redata['msg'] = "将用户从到用户组删除错误: {$oRet->response->error->message}";
            }
            else {
                Log::record( "将用户从到用户组删除错误: HTTP status code: $oRet->status\n");
                $redata['msg'] = "将用户从到用户组删除错误: HTTP status code: $oRet->status";
            }
        }
        return $redata;
    }

    // ========   用户相关方法结束 ========


    // ========   流程相关方法开始 ========

    private function getWorkflowIdByName($pmWorkspace,$token,$workflowName){
        //查看所有流程定义
        $oRet = $this->pmRestRequest("GET", "/api/1.0/$pmWorkspace/project", null, $token);
        $projectId = null;
        if ($oRet->status == 200) {
            foreach ($oRet->response as $oProject) {
                //echo 'projId:'.$oProject->prj_uid.",name:".$oProject->prj_name."<br/>".$workflowName;
                if ($workflowName == $oProject->prj_name) {
                   //print_r($oProject);
                    $projectId = $oProject->prj_uid;
                    break;
                }
            }
        }
       
        return $projectId;
    }

    /**
     * 启动流程实例
     * @param $wfName 流程名称
     * @param $wfvars 流程变量，是个键值对数组
     * @return mixed
     * @throws \Exception
     */
        public function startWorkflow($wfName,$wfvars){
        $pmWorkspace = C('PMWORKFLOW_CONFIG.WORKSAPCE');
        $token = $this->getPmToken();
        $redata['status'] = 0;
        $projectId = $this->getWorkflowIdByName($pmWorkspace,$token,$wfName);
        if(empty($projectId)){
            $redata['msg'] = "获取流程ID为空,启动流程失败";
            return $redata;
        }
        $taskId = '';
        //获取流程的开始任务
        $oRet = $this->pmRestRequest("GET", "/api/1.0/$pmWorkspace/project/$projectId/starting-tasks", null, $token);
        if ($oRet->status == 200) {
            foreach ($oRet->response as $oTask) {
                // print_r($oTask);
                $taskId = $oTask->act_uid;
               // echo 'taskId:'.$taskId.",name:".$oTask->act_name."<br/>";
            }
        }

        if(empty($taskId)){
            $redata['msg'] = "获取流程的开始任务ID为空,启动流程失败";
            return $redata;
        }

//启动流程的流程变量
        $uid = is_login();
        $wfvars['startpmuid'] = S("pm_usr_uid_".$uid); ; //流程发起用户pm_usr_uid
        $aCaseVars = array($wfvars);

//启动流程参数
        $aVars = array(
            'pro_uid'   => $projectId,
            'tas_uid'   => $taskId,
            'variables' => $aCaseVars
        );
       //启动流程
        //print_r($aVars);
        $oRet = $this->pmRestRequest("POST", "/api/1.0/{$pmWorkspace}/cases", $aVars,$token);
        //print_r($oRet);

        $app_uid=null;
        if ($oRet->status == 200) {
            $app_uid = $oRet->response->app_uid;
           // print "New Case {$oRet->response->app_number},{$oRet->response->app_uid} created.\n";
        }else{
            if ($oRet->response and isset($oRet->response->error)) {
                Log::record( "创建流程实例错误: {$oRet->response->error->code}\n" .
                    "Message: {$oRet->response->error->message}\n");
                $redata['msg'] = "创建流程实例错误: {$oRet->response->error->message}";
            }
            else {
                Log::record( "创建流程实例错误: HTTP status code: $oRet->status\n");
                $redata['msg'] = "创建流程实例错误: HTTP status code: $oRet->status";
            }
        }

        if(empty($app_uid)){
            $redata['msg'] = "流程实例ID为空,启动流程失败";
            return $redata;
        }

        $redata = $this->gonext($app_uid,1);
        if($redata['status'] == 1){
            $redata['msg'] = "流程创建成功并完成开始任务";
            $redata['app_uid'] = $app_uid;
        }
        return $redata;
    }

    /**
     * 去下一步
     * 调用此方法 会完成当前任务后流转到下一步
     * @param $pm_app_uid
     * @param int $task_index
     * @throws \Exception
     */
    public function gonext($pm_app_uid,$del_index = 1){
        $pmWorkspace = C('PMWORKFLOW_CONFIG.WORKSAPCE');
        $token = $this->getPmToken();
        //这个del_index参数必须有，开始任务的序号为1，其他任务从task信息中获取
        $aParams = array(
            "del_index" => $del_index
        );

        $redata['status'] = 0;
        $oRet = $this->pmRestRequest("put", "/api/1.0/$pmWorkspace/cases/{$pm_app_uid}/route-case",$aParams,$token);
        if ($oRet and $oRet->status == 200) {
            $redata['status'] = 1;
            //print "start task routed.\n";
        }else{
            if ($oRet->response and isset($oRet->response->error)) {
                Log::record( "创建流程实例错误: {$oRet->response->error->code}\n" .
                    "Message: {$oRet->response->error->message}\n");
                $redata['msg'] = "创建流程实例错误: {$oRet->response->error->message}";
            }
            else {
                Log::record( "创建流程实例错误: HTTP status code: $oRet->status\n");
                $redata['msg'] = "创建流程实例错误: HTTP status code: $oRet->status";
            }
        }
        return $redata;
    }

    /**
     * 设置流程实例变量值
     * 调用此方法 更改指定变量的值或创建变量
     * @param $pm_app_uid
     * @param array $wfvars 变量数组，如果变量已经存在则更新，否则就创建
     * @throws \Exception
     * return 变量数组，返回流程实例的所有变量数组
     */
    public function getvariable($pm_app_uid){
        $pmWorkspace = C('PMWORKFLOW_CONFIG.WORKSAPCE');
        $token = $this->getPmToken();

        $oRet = $this->pmRestRequest("get", "/api/1.0/{$pmWorkspace}/cases/{$pm_app_uid}/variables",null,$token);
        //print_r($oRet);
        if ($oRet and $oRet->status == 200) {
            $oVars = $oRet->response;
            //print_r($oVars);
            $redata = json_decode(json_encode($oVars),true);
        }else{
            $redata = array();
        }
        return $redata;
    }

    /**
     * 设置流程实例变量值
     * 调用此方法 更改指定变量的值或创建变量
     * @param $pm_app_uid
     * @param array $wfvars 变量数组，如果变量已经存在则更新，否则就创建
     * @throws \Exception
     */
    public function setvariable($pm_app_uid,$wfvars){
        $redata['status'] = 0;
        if(empty($wfvars)){
            $redata['msg'] = "变量不能为空";
            return $redata;
        }
        $pmWorkspace = C('PMWORKFLOW_CONFIG.WORKSAPCE');
        $token = $this->getPmToken();

        $oRet = $this->pmRestRequest("put", "/api/1.0/{$pmWorkspace}/cases/{$pm_app_uid}/variable",$wfvars,$token);
        if ($oRet and $oRet->status == 200) {
            $redata['status'] = 1;
            //print "variable updated.\n";
        }else{
            if ($oRet->response and isset($oRet->response->error)) {
                Log::record( "设置流程实例变量错误: {$oRet->response->error->code}\n" .
                    "Message: {$oRet->response->error->message}\n");
                $redata['msg'] = "设置流程实例变量错误: {$oRet->response->error->message}";
            }
            else {
                Log::record( "设置流程实例变量错误: HTTP status code: $oRet->status\n");
                $redata['msg'] = "设置流程实例变量错误: HTTP status code: $oRet->status";
            }
        }
        return $redata;
    }

    /**
     * 获取当前用户的todo任务列表
     *
     * 返回数组
     *  status 结果状态，1成功，0失败
     *  msg 结果信息
     *  datas 代办任务对象数组
     *  代办任务都系属性
     * "app_uid":	Unique ID of case.	"50576446953235bfb797531078087088"
    "del_index":	Delegation index of case, which counts tasks executed in the case, starting from 1.	"1"
    "del_last_index":	Last delegation index, which is the previous task in the case.	"1"
    "app_number":	The Case Number, which counts cases in the workspace, starting from 1.	"66"
    "app_status":	Current status of case: "TO_DO" (current task is assigned but not yet worked on), "DRAFT" (current task has been worked on, but not yet completed), "COMPLETED" (case terminated at an end event), "CANCELLED", "PAUSED", "DELETED" or "UNASSIGNED" (unclaimed self service cases)	"TO_DO"
    "usr_uid":	Unique ID of user currently assigned to work on case.	"00000000000000000000000000000001"
    "previous_usr_uid":	Unique ID of the previous user assigned to case. Set to empty string if the first task in the case and the current user is the first user assigned to the case.	""
    "tas_uid":	Unique ID of current task in case.	"7983935495320c1a75e1df6068322280"
    "pro_uid":	Unique ID of the case's process.	"2317283235320c1a36972b2028131767"
    "del_delegate_date":	Datetime in "YYYY-MM-DD HH:MM:SS" format when case was routed to the current task.	"2014-03-14 15:43:55"
    "del_init_date":	Datetime in "YYYY-MM-DD HH:MM:SS" format when current task was initiated. If a self service task which hasn't yet been claimed by a user, then set to null.	"2014-03-14 15:43:55"
    "del_task_due_date":	Datetime in "YYYY-MM-DD HH:MM:SS" format when the current task is due (scheduled to be completed).	"2014-03-17 15:43:55"
    "del_finish_date":	Datetime in "YYYY-MM-DD HH:MM:SS" format when the current task was completed. Set to null if not yet completed.	null
    "del_thread_status":	Status of the delegation thread which can be "OPEN" or "CLOSED", which indicates whether the current parallel task is still executing or has been completed or canceled.	"OPEN"
    "app_thread_status":	Status of the case thread which can be "OPEN" or "CLOSED", which indicates whether the current task is still executing or has been completed or canceled.	"OPEN"
    "app_title":	The case title, which by default is its case number, but can be customized by task properties.	"#66"
    "app_pro_title":	The title for the case's process.	"My process title"
    "app_tas_title":	The title of the current task in the case.	"Task 1"
    "app_current_user":	The last name and first name (separated by space) of the user currently assigned to the case.	" Administrator"
    "app_del_previous_user":	The last name and first name (separated by space) of the user assigned to the case's previous task.	""
    "del_priority":	The case's delegation priority which can be "VERY LOW" (1), "LOW" (2), "NORMAL" (3), "HIGH" (4) and "VERY HIGH" (5).	"NORMAL"
    "del_duration":	No longer used and always set to "0".	"0"
    "del_queue_duration":	No longer used and always set to "0".	"0"
    "del_delay_duration":	No longer used and always set to "0".	"0"
    "del_started": "0",	No longer used and always set to "0".	"0"
    "del_finished": "0",	No longer used and always set to "0".	"0"
    "del_delayed": "0",	No longer used and always set to "0".	"0"
    "app_create_date":	Datetime in "YYYY-MM-DD HH:MM:SS" format when the case was first created.	"2014-03-14 15:43:55"
    "app_finish_date":	Datetime in "YYYY-MM-DD HH:MM:SS" format when the case was completed or canceled. Set to null if not yet completed.	null
    "app_update_date":	Datetime in "YYYY-MM-DD HH:MM:SS" format when the case was last updated, meaning data was changed, files were uploaded or the case was routed to another task.	"2014-03-14 15:43:57"
    "app_overdue_percentage":	No longer used and always set to "0".	"0"
    "usr_firstname":	First name of the user currently assigned to work on case.	"Administrator"
    "usr_lastname":	Last name of the user currently assigned to work on case.	" "
    "usr_username":	Username of the user currently assigned to work on case.	"admin"
    "appcvcr_app_tas_title":	Title of the current task in the case.	"Task 1"
    "usrcr_usr_uid":	Unique ID of the user currently assigned to work on case.	"00000000000000000000000000000001"
    "usrcr_usr_firstname":	First name of the user currently assigned to work on case.	"Administrator"
    "usrcr_usr_lastname":	Last name of the user currently assigned to work on case.	" "
    "usrcr_usr_username":	Username of the user currently assigned to work on case.	"admin"
    "app_status_label":	The current case status, which can be "To do", "Draft", "Completed", "Cancelled", "Paused" or "Deleted".	"To do"

     返回任务列表 todo 示例：
    [
    {
    "app_uid": "50576446953235bfb797531078087088",
    "del_index": "1",
    "del_last_index": "1",
    "app_number": "1",
    "app_status": "ID_DRAFT",
    "usr_uid": "00000000000000000000000000000001",
    "previous_usr_uid": "",
    "tas_uid": "7983935495320c1a75e1df6068322280",
    "pro_uid": "2317283235320c1a36972b2028131767",
    "del_delegate_date": "2014-03-14 15:43:55",
    "del_init_date": "2014-03-14 15:43:55",
    "del_task_due_date": "2014-03-17 15:43:55",
    "del_finish_date": null,
    "del_thread_status": "OPEN",
    "app_thread_status": "OPEN",
    "app_title": "#1",
    "app_pro_title": "My process title",
    "app_tas_title": "Task 1",
    "app_current_user": " Administrator",
    "app_del_previous_user": "",
    "del_duration": "0",
    "del_queue_duration": "0",
    "del_delay_duration": "0",
    "del_started": "0",
    "del_finished": "0",
    "del_delayed": "0",
    "app_create_date": "2014-03-14 15:43:55",
    "app_finish_date": null,
    "app_update_date": "2014-03-14 15:43:57",
    "app_overdue_percentage": "0",
    "usr_firstname": "Administrator",
    "usr_lastname": " ",
    "usr_username": "admin",
    "appcvcr_app_tas_title": "Task 1",
    "usrcr_usr_uid": "00000000000000000000000000000001",
    "usrcr_usr_firstname": "Administrator",
    "usrcr_usr_lastname": " ",
    "usrcr_usr_username": "admin"
    }
    ]

     *
     */
    public function gettodo(){
        $pmWorkspace = C('PMWORKFLOW_CONFIG.WORKSAPCE');
        $token = $this->getPmToken();
        $redata['status'] = 0;
        $oRet = $this->pmRestRequest("GET", "/api/1.0/{$pmWorkspace}/cases", null, $token);
        if ($oRet->status == 200) {
            // print_r($oRet);
           // $case = null;
            /*foreach ($oRet->response as $oCase) {
                //echo(json_encode($oCase));
                //$case = $oCase;
               // echo "<br/>app_uid:{$oCase->app_uid},del_index:{$oCase->del_index},taskname:{$oCase->task_name}<br/>";
            }*/
            $redata['status'] = 1;
            $todojson = json_encode($oRet->response);
            $redata['datas'] = json_decode($todojson,true);
        }else{
            $uid = is_login();
            if ($oRet->response and isset($oRet->response->error)) {
                Log::record( "获取用户[{$uid}]代办任务列表错误: {$oRet->response->error->code}\n" .
                    "Message: {$oRet->response->error->message}\n");
                $redata['msg'] = "获取代办任务列表错误: {$oRet->response->error->message}";
            }
            else {
                Log::record( "获取用户[{$uid}]代办任务列表错误: HTTP status code: $oRet->status\n");
                $redata['msg'] = "获取代办任务列表错误: HTTP status code: $oRet->status";
            }
        }
        return $redata;
    }

    /**
     * 分页获取当前用户的todo任务列表
     * 参数
     * @param pageindex 开始页数，默认为0
     * @param pagesize 每页记录数，默认为25
     * @param title 待查询任务标题关键字
     *
     * 返回数组
     *  status 结果状态，1成功，0失败
     *  msg 结果信息
     *  datas 代办任务page对象
     *
     * "total": 6,	Total number of cases found.
    "start": 1,	Number where the list of cases begins. The default is 1.
    "limit": 25,	Maximum number of cases returned. The default is 25.
    "sort": "app_cache_view.app_number",	The field in the wf_<WORKSPACE>.APP_CACHE_VIEW table which is used to sort the cases. The default is "app_cache_view.app_number".
    "dir": "desc",	The sort order of the cases, which can be "asc" (ascending) or "desc" (descending, which is the default).
    "cat_uid": "",	The unique ID of a process category. Only cases whose processes are in the given category will be returned.
    "pro_uid": "",	The unique ID of a process. Only cases in the given process will be returned.
    "search": "",	A case insensitive string to search for in the case title and task title.
    "data":	 An array of case objects.代办任务列表数组
     *
     *  代办任务都系属性
     *
     * "app_uid":	Unique ID of case.	"50576446953235bfb797531078087088"
    "del_index":	Delegation index of case, which counts tasks executed in the case, starting from 1.	"1"
    "del_last_index":	Last delegation index, which is the previous task in the case.	"1"
    "app_number":	The Case Number, which counts cases in the workspace, starting from 1.	"66"
    "app_status":	Current status of case: "TO_DO" (current task is assigned but not yet worked on), "DRAFT" (current task has been worked on, but not yet completed), "COMPLETED" (case terminated at an end event), "CANCELLED", "PAUSED", "DELETED" or "UNASSIGNED" (unclaimed self service cases)	"TO_DO"
    "usr_uid":	Unique ID of user currently assigned to work on case.	"00000000000000000000000000000001"
    "previous_usr_uid":	Unique ID of the previous user assigned to case. Set to empty string if the first task in the case and the current user is the first user assigned to the case.	""
    "tas_uid":	Unique ID of current task in case.	"7983935495320c1a75e1df6068322280"
    "pro_uid":	Unique ID of the case's process.	"2317283235320c1a36972b2028131767"
    "del_delegate_date":	Datetime in "YYYY-MM-DD HH:MM:SS" format when case was routed to the current task.	"2014-03-14 15:43:55"
    "del_init_date":	Datetime in "YYYY-MM-DD HH:MM:SS" format when current task was initiated. If a self service task which hasn't yet been claimed by a user, then set to null.	"2014-03-14 15:43:55"
    "del_task_due_date":	Datetime in "YYYY-MM-DD HH:MM:SS" format when the current task is due (scheduled to be completed).	"2014-03-17 15:43:55"
    "del_finish_date":	Datetime in "YYYY-MM-DD HH:MM:SS" format when the current task was completed. Set to null if not yet completed.	null
    "del_thread_status":	Status of the delegation thread which can be "OPEN" or "CLOSED", which indicates whether the current parallel task is still executing or has been completed or canceled.	"OPEN"
    "app_thread_status":	Status of the case thread which can be "OPEN" or "CLOSED", which indicates whether the current task is still executing or has been completed or canceled.	"OPEN"
    "app_title":	The case title, which by default is its case number, but can be customized by task properties.	"#66"
    "app_pro_title":	The title for the case's process.	"My process title"
    "app_tas_title":	The title of the current task in the case.	"Task 1"
    "app_current_user":	The last name and first name (separated by space) of the user currently assigned to the case.	" Administrator"
    "app_del_previous_user":	The last name and first name (separated by space) of the user assigned to the case's previous task.	""
    "del_priority":	The case's delegation priority which can be "VERY LOW" (1), "LOW" (2), "NORMAL" (3), "HIGH" (4) and "VERY HIGH" (5).	"NORMAL"
    "del_duration":	No longer used and always set to "0".	"0"
    "del_queue_duration":	No longer used and always set to "0".	"0"
    "del_delay_duration":	No longer used and always set to "0".	"0"
    "del_started": "0",	No longer used and always set to "0".	"0"
    "del_finished": "0",	No longer used and always set to "0".	"0"
    "del_delayed": "0",	No longer used and always set to "0".	"0"
    "app_create_date":	Datetime in "YYYY-MM-DD HH:MM:SS" format when the case was first created.	"2014-03-14 15:43:55"
    "app_finish_date":	Datetime in "YYYY-MM-DD HH:MM:SS" format when the case was completed or canceled. Set to null if not yet completed.	null
    "app_update_date":	Datetime in "YYYY-MM-DD HH:MM:SS" format when the case was last updated, meaning data was changed, files were uploaded or the case was routed to another task.	"2014-03-14 15:43:57"
    "app_overdue_percentage":	No longer used and always set to "0".	"0"
    "usr_firstname":	First name of the user currently assigned to work on case.	"Administrator"
    "usr_lastname":	Last name of the user currently assigned to work on case.	" "
    "usr_username":	Username of the user currently assigned to work on case.	"admin"
    "appcvcr_app_tas_title":	Title of the current task in the case.	"Task 1"
    "usrcr_usr_uid":	Unique ID of the user currently assigned to work on case.	"00000000000000000000000000000001"
    "usrcr_usr_firstname":	First name of the user currently assigned to work on case.	"Administrator"
    "usrcr_usr_lastname":	Last name of the user currently assigned to work on case.	" "
    "usrcr_usr_username":	Username of the user currently assigned to work on case.	"admin"
    "app_status_label":	The current case status, which can be "To do", "Draft", "Completed", "Cancelled", "Paused" or "Deleted".	"To do"


     * 返回page对象示例：
    {
    "start": 0,
    "limit": 1,
    "total": 25,
    "process": "",
    "category": "",
    "search": "",
    "data": [
    {
    "app_uid": "50576446953235bfb797531078087088",
    "del_index": "1",
    "del_last_index": "1",
    "app_number": "1",
    "app_status": "ID_DRAFT",
    "usr_uid": "00000000000000000000000000000001",
    "previous_usr_uid": "",
    "tas_uid": "7983935495320c1a75e1df6068322280",
    "pro_uid": "2317283235320c1a36972b2028131767",
    "del_delegate_date": "2014-03-14 15:43:55",
    "del_init_date": "2014-03-14 15:43:55",
    "del_task_due_date": "2014-03-17 15:43:55",
    "del_finish_date": null,
    "del_thread_status": "OPEN",
    "app_thread_status": "OPEN",
    "app_title": "#1",
    "app_pro_title": "Invoice Approval Process",
    "app_tas_title": "Task 1",
    "app_current_user": " Administrator",
    "app_del_previous_user": "",
    "del_duration": "0",
    "del_queue_duration": "0",
    "del_delay_duration": "0",
    "del_started": "0",
    "del_finished": "0",
    "del_delayed": "0",
    "app_create_date": "2014-03-14 15:43:55",
    "app_finish_date": null,
    "app_update_date": "2014-03-14 15:43:57",
    "app_overdue_percentage": "0",
    "usr_firstname": "Administrator",
    "usr_lastname": " ",
    "usr_username": "admin",
    "appcvcr_app_tas_title": "Task 1",
    "usrcr_usr_uid": "00000000000000000000000000000001",
    "usrcr_usr_firstname": "Administrator",
    "usrcr_usr_lastname": " ",
    "usrcr_usr_username": "admin"
    }
    ]
    }
     * @return mixed
     * @throws \Exception
     */
    public function gettodobypage($pageindex=0,$pagesize=25,$title=null){
        $pmWorkspace = C('PMWORKFLOW_CONFIG.WORKSAPCE');
        $token = $this->getPmToken();
        $redata['status'] = 0;
        $filterParams = array(
            "start" => $pageindex,
            "limit" => $pagesize,
        );

        if(!empty($title)){
            $filterParams['search']=urlencode($title);
        }

        $oRet = $this->pmRestRequest("GET", "/api/1.0/{$pmWorkspace}/cases/paged", $filterParams, $token);
        if ($oRet->status == 200) {
            $redata['status'] = 1;
            $todojson = json_encode($oRet->response);
            $redata['datas'] = json_decode($todojson,true);
        }else{
            $uid = is_login();
            if ($oRet->response and isset($oRet->response->error)) {
                Log::record( "获取用户[{$uid}]代办任务列表错误: {$oRet->response->error->code}\n" .
                    "Message: {$oRet->response->error->message}\n");
                $redata['msg'] = "获取代办任务列表错误: {$oRet->response->error->message}";
            }
            else {
                Log::record( "获取用户[{$uid}]代办任务列表错误: HTTP status code: $oRet->status\n");
                $redata['msg'] = "获取代办任务列表错误: HTTP status code: $oRet->status";
            }
        }
        return $redata;
    }

    /**
     * 分页获取当前用户的已参与任务列表（已办任务列表）
     * 参数
     * @param pageindex 开始页数，默认为0
     * @param pagesize 每页记录数，默认为25
     * @param title 待查询任务标题关键字
     *
     * 返回数组
     *  status 结果状态，1成功，0失败
     *  msg 结果信息
     *  datas 已办任务page对象
     *
     * "total": 6,	Total number of cases found.
    "start": 1,	Number where the list of cases begins. The default is 1.
    "limit": 25,	Maximum number of cases returned. The default is 25.
    "sort": "app_cache_view.app_number",	The field in the wf_<WORKSPACE>.APP_CACHE_VIEW table which is used to sort the cases. The default is "app_cache_view.app_number".
    "dir": "desc",	The sort order of the cases, which can be "asc" (ascending) or "desc" (descending, which is the default).
    "cat_uid": "",	The unique ID of a process category. Only cases whose processes are in the given category will be returned.
    "pro_uid": "",	The unique ID of a process. Only cases in the given process will be returned.
    "search": "",	A case insensitive string to search for in the case title and task title.
    "data":	 An array of case objects.代办任务列表数组
     *
     *  代办任务都系属性
     *
     * "app_uid":	Unique ID of case.	"50576446953235bfb797531078087088" 流程实例ID
    "del_index":	Delegation index of case, which counts tasks executed in the case, starting from 1.	"1"
    "del_last_index":	Last delegation index, which is the previous task in the case.	"1"
    "app_number":	The Case Number, which counts cases in the workspace, starting from 1.	"66"
    "app_status":	Current status of case: "TO_DO" (current task is assigned but not yet worked on), "DRAFT" (current task has been worked on, but not yet completed), "COMPLETED" (case terminated at an end event), "CANCELLED", "PAUSED", "DELETED" or "UNASSIGNED" (unclaimed self service cases)	"TO_DO"
    "usr_uid":	Unique ID of user currently assigned to work on case.	"00000000000000000000000000000001"
    "previous_usr_uid":	Unique ID of the previous user assigned to case. Set to empty string if the first task in the case and the current user is the first user assigned to the case.	""
    "tas_uid":	Unique ID of current task in case.	"7983935495320c1a75e1df6068322280"
    "pro_uid":	Unique ID of the case's process.	"2317283235320c1a36972b2028131767"
    "del_delegate_date":	Datetime in "YYYY-MM-DD HH:MM:SS" format when case was routed to the current task.	"2014-03-14 15:43:55"
    "del_init_date":	Datetime in "YYYY-MM-DD HH:MM:SS" format when current task was initiated. If a self service task which hasn't yet been claimed by a user, then set to null.	"2014-03-14 15:43:55"
    "del_task_due_date":	Datetime in "YYYY-MM-DD HH:MM:SS" format when the current task is due (scheduled to be completed).	"2014-03-17 15:43:55"
    "del_finish_date":	Datetime in "YYYY-MM-DD HH:MM:SS" format when the current task was completed. Set to null if not yet completed.	null
    "del_thread_status":	Status of the delegation thread which can be "OPEN" or "CLOSED", which indicates whether the current parallel task is still executing or has been completed or canceled.	"OPEN"
    "app_thread_status":	Status of the case thread which can be "OPEN" or "CLOSED", which indicates whether the current task is still executing or has been completed or canceled.	"OPEN"
    "app_title":	The case title, which by default is its case number, but can be customized by task properties.	"#66"
    "app_pro_title":	The title for the case's process.	"My process title"
    "app_tas_title":	The title of the current task in the case.	"Task 1"
    "app_current_user":	The last name and first name (separated by space) of the user currently assigned to the case.	" Administrator"
    "app_del_previous_user":	The last name and first name (separated by space) of the user assigned to the case's previous task.	""
    "del_priority":	The case's delegation priority which can be "VERY LOW" (1), "LOW" (2), "NORMAL" (3), "HIGH" (4) and "VERY HIGH" (5).	"NORMAL"
    "del_duration":	No longer used and always set to "0".	"0"
    "del_queue_duration":	No longer used and always set to "0".	"0"
    "del_delay_duration":	No longer used and always set to "0".	"0"
    "del_started": "0",	No longer used and always set to "0".	"0"
    "del_finished": "0",	No longer used and always set to "0".	"0"
    "del_delayed": "0",	No longer used and always set to "0".	"0"
    "app_create_date":	Datetime in "YYYY-MM-DD HH:MM:SS" format when the case was first created.	"2014-03-14 15:43:55"
    "app_finish_date":	Datetime in "YYYY-MM-DD HH:MM:SS" format when the case was completed or canceled. Set to null if not yet completed.	null
    "app_update_date":	Datetime in "YYYY-MM-DD HH:MM:SS" format when the case was last updated, meaning data was changed, files were uploaded or the case was routed to another task.	"2014-03-14 15:43:57"
    "app_overdue_percentage":	No longer used and always set to "0".	"0"
    "usr_firstname":	First name of the user currently assigned to work on case.	"Administrator"
    "usr_lastname":	Last name of the user currently assigned to work on case.	" "
    "usr_username":	Username of the user currently assigned to work on case.	"admin"
    "appcvcr_app_tas_title":	Title of the current task in the case.	"Task 1"
    "usrcr_usr_uid":	Unique ID of the user currently assigned to work on case.	"00000000000000000000000000000001"
    "usrcr_usr_firstname":	First name of the user currently assigned to work on case.	"Administrator"
    "usrcr_usr_lastname":	Last name of the user currently assigned to work on case.	" "
    "usrcr_usr_username":	Username of the user currently assigned to work on case.	"admin"
    "app_status_label":	The current case status, which can be "To do", "Draft", "Completed", "Cancelled", "Paused" or "Deleted".	"To do"


     * 返回page对象示例：
    {
    "start": 0,
    "limit": 1,
    "total": 25,
    "process": "",
    "category": "",
    "search": "",
    "data": [
    {
    "app_uid": "50576446953235bfb797531078087088",
    "del_index": "1",
    "del_last_index": "1",
    "app_number": "1",
    "app_status": "ID_DRAFT",
    "usr_uid": "00000000000000000000000000000001",
    "previous_usr_uid": "",
    "tas_uid": "7983935495320c1a75e1df6068322280",
    "pro_uid": "2317283235320c1a36972b2028131767",
    "del_delegate_date": "2014-03-14 15:43:55",
    "del_init_date": "2014-03-14 15:43:55",
    "del_task_due_date": "2014-03-17 15:43:55",
    "del_finish_date": null,
    "del_thread_status": "OPEN",
    "app_thread_status": "OPEN",
    "app_title": "#1",
    "app_pro_title": "Invoice Approval Process",
    "app_tas_title": "Task 1",
    "app_current_user": " Administrator",
    "app_del_previous_user": "",
    "del_duration": "0",
    "del_queue_duration": "0",
    "del_delay_duration": "0",
    "del_started": "0",
    "del_finished": "0",
    "del_delayed": "0",
    "app_create_date": "2014-03-14 15:43:55",
    "app_finish_date": null,
    "app_update_date": "2014-03-14 15:43:57",
    "app_overdue_percentage": "0",
    "usr_firstname": "Administrator",
    "usr_lastname": " ",
    "usr_username": "admin",
    "appcvcr_app_tas_title": "Task 1",
    "usrcr_usr_uid": "00000000000000000000000000000001",
    "usrcr_usr_firstname": "Administrator",
    "usrcr_usr_lastname": " ",
    "usrcr_usr_username": "admin"
    }
    ]
    }
     * @return mixed
     * @throws \Exception
     */
    public function getdonetaskbypage($pageindex=0,$pagesize=25,$title=null){
        $pmWorkspace = C('PMWORKFLOW_CONFIG.WORKSAPCE');
        $token = $this->getPmToken();
        $redata['status'] = 0;
        $filterParams = array(
            "start" => $pageindex,
            "limit" => $pagesize,
        );

        if(!empty($title)){
            $filterParams['search']=urlencode($title);
        }

        $oRet = $this->pmRestRequest("GET", "/api/1.0/{$pmWorkspace}/cases/participated/paged", $filterParams, $token);
        if ($oRet->status == 200) {
            $redata['status'] = 1;
            $donejson = json_encode($oRet->response);
            $redata['datas'] = json_decode($donejson,true);
        }else{
            $uid = is_login();
            if ($oRet->response and isset($oRet->response->error)) {
                Log::record( "获取用户[{$uid}]已办任务列表错误: {$oRet->response->error->code}\n" .
                    "Message: {$oRet->response->error->message}\n");
                $redata['msg'] = "获取已办任务列表错误: {$oRet->response->error->message}";
            }
            else {
                Log::record( "获取用户[{$uid}]已办任务列表错误: HTTP status code: $oRet->status\n");
                $redata['msg'] = "获取已办任务列表错误: HTTP status code: $oRet->status";
            }
        }
        return $redata;
    }

    /**
     * 获取指定流程实例的任务列表
     * 可用于调试
     * @param $app_uid
     * @return mixed
     * @throws \Exception
     */
    public function getcasetasks($app_uid){
        $pmWorkspace = C('PMWORKFLOW_CONFIG.WORKSAPCE');
        $token = $this->getPmToken();
        $redata['status'] = 0;

        $oRet = $this->pmRestRequest("GET", "/api/1.0/$pmWorkspace/cases/$app_uid/tasks", null, $token);
        if ($oRet->status == 200) {
            $redata['status'] = 1;
            $donejson = json_encode($oRet->response);
            $redata['datas'] = json_decode($donejson,true);
        }else{
            if ($oRet->response and isset($oRet->response->error)) {
                Log::record( "获取实例[{$app_uid}]任务列表错误: {$oRet->response->error->code}\n" .
                    "Message: {$oRet->response->error->message}\n");
                $redata['msg'] = "获取实例任务列表错误: {$oRet->response->error->message}";
            }
            else {
                Log::record( "获取实例[{$app_uid}]任务列表错误: HTTP status code: $oRet->status\n");
                $redata['msg'] = "获取实例任务列表错误: HTTP status code: $oRet->status";
            }
        }
        return $redata;
    }


    /**
     * 取消指定流程实例
     * @param $app_uid 流程实例ID
     * @return mixed 返回结果数组，status为1表示成功，0为失败,msg 为结果消息
     * @throws \Exception
     *
     */
    public function cancelWorkflow($app_uid){
        $pmWorkspace = C('PMWORKFLOW_CONFIG.WORKSAPCE');
        $token = $this->getPmToken();
        $redata['status'] = 0;

        $oRet = $this->pmRestRequest("put", "/api/1.0/{$pmWorkspace}/cases/{$app_uid}/cancel", null, $token);
        if ($oRet->status == 200) {
            $redata['status'] = 1;
            $redata['msg'] = "取消流程实例成功";
        }else{
            if ($oRet->response and isset($oRet->response->error)) {
                Log::record( "取消流程实例[{$app_uid}]错误: {$oRet->response->error->code}\n" .
                    "Message: {$oRet->response->error->message}\n");
                $redata['msg'] = "取消流程实例错误: {$oRet->response->error->message}";
            }
            else {
                Log::record( "取消流程实例[{$app_uid}]错误: HTTP status code: $oRet->status\n");
                $redata['msg'] = "取消流程实例错误: HTTP status code: $oRet->status";
            }
        }
        return $redata;
    }

    // ========   流程相关方法结束 ========


} 